#ifndef CONSOLE_HPP
#define CONSOLE_HPP

#include <QApplication>
#include <QObject>
#include <QPlainTextEdit>
#include <QTextBlock>
#include <QPushButton>
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>

using namespace std;

#include "przedmiot.hpp"
#include "wyposazenie.hpp"
#include "pulapkazdr.hpp"
#include "postac.hpp"
#include "przeciwnik.hpp"
#include "bohater.hpp"
#include "labirynt.hpp"

#define ENEMIES 3



class Console : public QObject
{
    Q_OBJECT

private:

    QPlainTextEdit* console;
    QPushButton* area[11][11];
    Labirynt labirynth;
    Bohater hero;
    Przeciwnik enemy;
    QString answerSign = "< ";
    QString chooseHeroCommand = "Podaj swoje imię:";



    void setCursorAtEnd()
    {
        QTextCursor cursor(console->textCursor());
        cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
        console->setTextCursor(cursor);
        console->setFocus();
    }



    void tellStory()
    {
        console->appendPlainText(prepareAnswer() + "Budzisz się w ciasnym tunelu. Ostatnie, co pamiętasz, to badanie ruin pewnej starożytnej cywilizacji, podczas którego nagle straciłeś przytomność. Na ścianie obok ciebie są zapisane sentencje w róźnych językach, większość z nich dotyczy jakiegoś labiryntu i zła w nim uwięzionego. Z braku innych opcji postanawiasz się rozejrzeć po budowli i przekonać na własnej skórze, jakie zło się tu czai.");
        console->appendPlainText(prepareAnswer() + "Witaj w grze pt. \"Labirynt Tajemnic\". Jeśli chcesz poznać zasady sterowania postacią i gry, to wpisz \"pomoc\". W przeciwnym wypadku ruszaj na podbój labiryntu! Miłej zabawy, podróżniku!\n");
        prepareCommand();
    }



    void chooseHero()
    {
        console->appendPlainText(prepareAnswer() + chooseHeroCommand + "\n");
        prepareCommand();
    }



    void meetEnemy()
    {
        int x = rand() % ENEMIES;
        int strength = rand() % 3 + 1;
        int hitpoints = rand() % 3 + 1;
        string enemy_name = Przeciwnik::enemyName(x);
        int e = rand() % 3 + 1;
        QString enemy_picture = QString::fromStdString(Przeciwnik::enemyPicture(x));
        enemy = Przeciwnik(strength, hitpoints, enemy_name, e);
        area[hero.getY()][hero.getX()]->setIcon(QIcon(enemy_picture));

        int z = rand() % 2;
        QString message;
        if (z == 0) message = "Drogę zagradza Ci ";
        else message = "Na Twojej drodze staje ";
        console->appendPlainText(answerSign + message + QString::fromStdString(enemy_name) + ".\n");
        prepareCommand();
    }



public:

    Console()
    {

    }



    void setConsole(QPlainTextEdit* c, QPushButton* a[][11], Labirynt &l)
    {
        console = c;
        for (int i = 0; i < 11; i++)
        {
            for (int j = 0; j < 11; j++)
            {
                area[i][j] = a[i][j];
            }
        }
        labirynth = l;
    }



    QString getChooseHeroCommand()
    {
        return answerSign + chooseHeroCommand;
    }



    void prepareCommand()
    {
        setCursorAtEnd();
    }



    QString prepareAnswer()
    {
        setCursorAtEnd();
        return answerSign;
    }



    void prepareConsole()
    {
        console->setPlainText(answerSign + "WITAJ W LABIRYNCIE TAJEMNIC.");
        tellStory();
        chooseHero();
    }



    QString lastCommand()
    {
        QTextDocument* all_commands = console->document();
        QString command = all_commands->findBlockByNumber(all_commands->blockCount() - 1).text();
        return command;
    }



    QString secondLastCommand()
    {
        QTextDocument* all_commands = console->document();
        QString command = all_commands->findBlockByNumber(all_commands->blockCount() - 2).text();
        return command;
    }



    QString thirdLastCommand()
    {
        QTextDocument* all_commands = console->document();
        QString command = all_commands->findBlockByNumber(all_commands->blockCount() - 3).text();
        return command;
    }



    bool isAnswer()
    {
        if (lastCommand()[0] == answerSign[0])
        {
            return 1;
        }
        else return 0;
    }



    bool isCommand()
    {
        if (lastCommand()[0] == answerSign[0])
        {
            return 0;
        }
        else return 1;
    }



    //////////////////// KOMENDY OGÓLNE ////////////////////

    void help()
    {
        console->appendPlainText(prepareAnswer() + "Wpisuj dowolne komendy w naturalnym języku, aby poruszać bohaterem gry.\n");
        prepareCommand();
    }



    void setHeroName()
    {
        QString name = "Gość";
        if (secondLastCommand().length() > 0)
        {
            name = secondLastCommand();
        }
        hero.SetName(name.toStdString());
        console->appendPlainText(prepareAnswer() + "Witaj, " + QString::fromStdString(hero.RName()) + "!");
        console->appendPlainText(prepareAnswer() + "Twoje punkty:");
        QString value;
        console->appendPlainText(prepareAnswer() + "\t Siła:         \t" + value.number(hero.RAttributes('s')));
        console->appendPlainText(prepareAnswer() + "\t Zręczność:    \t" + value.number(hero.RAttributes('d')));
        console->appendPlainText(prepareAnswer() + "\t Punkty życia: \t" + value.number(hero.RAttributes('h')));
        console->appendPlainText(prepareAnswer() + "\t Doświadczenie:\t" + value.number(hero.RAttributes('e')));
        console->appendPlainText(prepareAnswer() + "\t Poziom:       \t" + value.number(hero.RAttributes('l')) + "\n");
        prepareCommand();
    }



    //////////////////// KOMENDY SZCZEGÓŁOWE ////////////////////

    void not()
    {
        console->appendPlainText(answerSign + "Skoro nie, to nie.\n");
        prepareCommand();
    }



    void ok()
    {
        console->appendPlainText(answerSign + "Dobrze.\n");
        prepareCommand();
    }



    void newGame()
    {
        for (int i = 0; i < 11; i++)
        {
            for (int j = 0; j < 11; j++)
            {
                area[i][j]->setStyleSheet("background-color: black;");
            }
        }
        area[0][0]->setStyleSheet("background-color: green;");
        area[0][0]->setIcon(QIcon(":/pictures/resources/hero.png"));
        console->appendPlainText(answerSign + "Zaczynasz nową grę.\n");
        hero.SetValue('x', 0);
        hero.SetValue('y', 0);
        hero.withEnemy = 0;
        prepareCommand();
    }



    void endGame()
    {
        console->appendPlainText(answerSign + "Kończysz grę.\n");
        prepareCommand();
        QApplication::quit();
    }



    void turnRight()
    {
        if (hero.getX() + 1 > 10 || labirynth.przejsciePrawo(hero.getY(), hero.getX()) == 1 || hero.withEnemy)
        {
            console->appendPlainText(answerSign + "Nie możesz skręcić w prawo.\n");
            prepareCommand();
        }
        else
        {
            QString icon = labirynth.areaPicture(hero.getY(), hero.getX());
            area[hero.getY()][hero.getX()]->setIcon(QIcon(icon));
            hero.AddToValue('x', 1);
            area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
            area[hero.getY()][hero.getX()]->setStyleSheet("background-color: green;");
            console->appendPlainText(answerSign + "Skręcasz w prawo.\n");
            prepareCommand();

            int b = rand() % 2;
            if (b == 1)
            {
                hero.withEnemy = 1;
                meetEnemy();
            }
            else hero.withEnemy = 0;
        }
    }



    void turnLeft()
    {
        if (hero.getX() - 1 < 0 || labirynth.przejscieLewo(hero.getY(), hero.getX()) == 1 || hero.withEnemy)
        {
            console->appendPlainText(answerSign + "Nie możesz skręcić w lewo.\n");
            prepareCommand();
        }
        else
        {
            QString icon = labirynth.areaPicture(hero.getY(), hero.getX());
            area[hero.getY()][hero.getX()]->setIcon(QIcon(icon));
            hero.AddToValue('x', -1);
            area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
            area[hero.getY()][hero.getX()]->setStyleSheet("background-color: green;");
            console->appendPlainText(answerSign + "Skręcasz w lewo.\n");
            prepareCommand();

            int b = rand() % 2;
            if (b == 1)
            {
                hero.withEnemy = 1;
                meetEnemy();
            }
            else hero.withEnemy = 0;
        }
    }



    void leftOrRight()
    {
        console->appendPlainText(answerSign + "Czy chcesz skręcić w prawo czy w lewo?\n");
        prepareCommand();
    }



    void goTop()
    {
        if (hero.getY() - 1 < 0 || labirynth.przejscieGora(hero.getY(), hero.getX()) == 1 || hero.withEnemy)
        {
            console->appendPlainText(answerSign + "Nie możesz pójść w górę.\n");
            prepareCommand();
        }
        else
        {
            QString icon = labirynth.areaPicture(hero.getY(), hero.getX());
            area[hero.getY()][hero.getX()]->setIcon(QIcon(icon));
            hero.AddToValue('y', -1);
            area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
            area[hero.getY()][hero.getX()]->setStyleSheet("background-color: green;");
            console->appendPlainText(answerSign + "Idziesz w górę.\n");
            prepareCommand();

            int b = rand() % 2;
            if (b == 1)
            {
                hero.withEnemy = 1;
                meetEnemy();
            }
            else hero.withEnemy = 0;
        }
    }



    void goDown()
    {
        if (hero.getY() + 1 > 10 || labirynth.przejscieDol(hero.getY(), hero.getX()) == 1 || hero.withEnemy)
        {
            console->appendPlainText(answerSign + "Nie możesz pójść w dół.\n");
            prepareCommand();
        }
        else
        {
            QString icon = labirynth.areaPicture(hero.getY(), hero.getX());
            area[hero.getY()][hero.getX()]->setIcon(QIcon(icon));
            hero.AddToValue('y', 1);
            area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
            area[hero.getY()][hero.getX()]->setStyleSheet("background-color: green;");
            console->appendPlainText(answerSign + "Idziesz w dół.\n");
            prepareCommand();

            int b = rand() % 2;
            if (b == 1)
            {
                hero.withEnemy = 1;
                meetEnemy();
            }
            else hero.withEnemy = 0;
        }
    }



    void killEnemy()
    {
        if (!hero.withEnemy || enemy.RAttributes('h') < 0)
        {
            console->appendPlainText(answerSign + QString::fromStdString(enemy.RName()) + " nie żyje!\n");
            area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
            hero.withEnemy = 0;
        }
        else
        {
            enemy.AddToValue('h', -1);
            int z = rand() % 2;
            QString message;
            if (z == 0) message = " został raniony!";
            else message = " został trafiony!";
            console->appendPlainText(answerSign + QString::fromStdString(enemy.RName()) + message + "\n");
            if (enemy.RAttributes('h') < 0)
            {
                console->appendPlainText(answerSign + QString::fromStdString(enemy.RName()) + " nie żyje!\n");
                area[hero.getY()][hero.getX()]->setIcon(QIcon(":/pictures/resources/hero.png"));
                hero.withEnemy = 0;
            }
        }
    }


    void callFunction(QString f)
    {
        if (f == "help") help();
        if (f == "not") not();
        if (f == "ok") ok();
        if (f == "newGame") newGame();
        if (f == "endGame") endGame();
        if (f == "turnRight") turnRight();
        if (f == "turnLeft") turnLeft();
        if (f == "leftOrRight") leftOrRight();
        if (f == "goTop") goTop();
        if (f == "goDown") goDown();
        if (f == "killEnemy") killEnemy();
    }



    void notUnderstand()
    {
        console->appendPlainText(answerSign + "Nie rozumiem polecenia.\n");
        prepareCommand();
    }
};



#endif // CONSOLE_HPP
